/*
    The NeonX Library

    Copyright (c) 2013 darkcat

    Code covered by the MIT License
*/

#pragma once

// nx...
#include "config/general.h"
// nx::atomic
#include "platform/atomic.h"
// nx::thread
#include "platform/thread.h"
// NonCopyable
#include "utility/noncopyable.h"
// nx_assert
#include "bugfix/assert.h"

//////////////////////////////////////////////////////////////////////////
NX_BEG
//////////////////////////////////////////////////////////////////////////

/*
    atomic lock
*/

class Lock : NonCopyable
{
protected:
    long           rc_;
    atomic::type_t id_;

public:
    Lock(void) : rc_(0), id_(0) {}
    virtual ~Lock() { nx_assert(rc_ <= 0); }

public:
    void lock(void)
    {
        thread::id_t tid = thread::current_id();
        if (id_ == (atomic::norm_t)tid)
            ++rc_;
        else
        {
            while(!atomic::cas(id_, 0, (atomic::norm_t)tid))
                thread::yield();
            rc_ = 1;
        }
    }
    void trylock(void)
    {
        thread::id_t tid = thread::current_id();
        if (id_ == (atomic::norm_t)tid)
            ++rc_;
        else
        {
            if (atomic::cas(id_, 0, (atomic::norm_t)tid))
                rc_ = 1;
        }
    }
    void unlock(void)
    {
        if (id_ == (atomic::norm_t)thread::current_id())
            if (--rc_ <= 0)
            {
                atomic::set(id_, 0);
                rc_ = 0;
            }
    }
};

typedef Lock lock_t;

//////////////////////////////////////////////////////////////////////////
NX_END
//////////////////////////////////////////////////////////////////////////
